Skip to content

feat!: v6 registry integration — serve plugins from @data-fair/registry#87

Merged
albanm merged 36 commits into
masterfrom
feat-registry
May 20, 2026
Merged

feat!: v6 registry integration — serve plugins from @data-fair/registry#87
albanm merged 36 commits into
masterfrom
feat-registry

Conversation

@albanm
Copy link
Copy Markdown
Member

@albanm albanm commented May 20, 2026

Summary

Major version (v6.0) reworking how processing plugins are stored and served.
Plugin code, schemas, metadata and access grants move fully into
@data-fair/registry; processings
becomes stateless with respect to plugin content.

Previously plugins lived on a persistent volume at dataDir/plugins/{id} with
sibling -access.json / -config.json / -metadata.json files, installed via a
superadmin-only POST /api/v1/plugins (npm pack + npm install). Now the API
and worker pull pre-built tarballs from the registry on demand into an ephemeral
per-container cache via registry's lib-node.

See docs/architecture/v6-registry-integration.md for the full design.

Changes

Registry integration

  • API and worker resolve plugins through ensureArtefact (lib-node-registry),
    downloading + extracting tarballs into ${tmpDir}/registry-cache on cache miss.
  • Registry is the single source of truth for plugin code, schemas, public/private
    flag, access grants and metadata — no mongo collection mirrors plugin state.
  • Plugin access control is delegated to the registry: the owner account is
    passed on every call, and a 403/404 from the registry surfaces directly,
    replacing the explicit access check in the create/update endpoints.
  • New shared/plugin-load.ts resolves a plugin entry point from
    package.json#main (supports pre-built JS or Node type-stripped TS).
  • New GET /processings/:id/plugin-config-schema reads processing-config-schema.json
    from the cached tarball (same convention as v5).

Removed

  • POST/GET/PUT/DELETE /api/v1/plugins endpoints and the on-disk plugin dir.
  • The plugins-registry router.
  • The UI admin "Plugins" page; the "create processing" picker now calls the
    registry directly (mounted at /registry on the same domain).

Broken-plugin processings UX

When a plugin is no longer available (deleted from the registry or access
revoked), processings using it are handled gracefully instead of erroring out:

  • Worker logs a friendly message on a run whose plugin is unavailable.
  • UI shows a "Plugin unavailable" badge (renamed from "Deleted") with a tooltip,
    an edit-page banner, and hides the form / exec / duplicate / change-owner
    actions while keeping the processing readable and deletable.

Config

  • New required privateRegistryUrl and secretKeys.registry
    (PRIVATE_REGISTRY_URL, SECRET_REGISTRY).
  • dataDir is now optional — when set it implies the legacy plugins volume is
    mounted (read-only, transitional; dropped in v7.0).

Migration

  • upgrade/5.2.0/01-publish-plugins-to-registry.ts — first-boot migration:
    re-tars each plugin dir (with node_modules) and uploads it to the registry,
    along with metadata and access grants. Fails fast on orphan processings.

Testing

  • New API/e2e specs: branch-plugin, broken-plugin, available-plugin.
  • New test support helpers: tests/support/registry.ts, data-fair.ts,
    PATCH /test-env/raw-processing/:id for invalid-state setups.
  • Removed obsolete plugins/install and plugins/registry specs.

Breaking changes

  • The legacy plugins volume and /api/v1/plugins API are gone. Deployments must
    configure privateRegistryUrl + SECRET_REGISTRY and run the 5.2.0 upgrade
    scripts. The legacy volume may stay mounted read-only through v6.0 for
    deprecated per-instance plugin-config; both are removed in v7.0.

albanm and others added 30 commits May 7, 2026 16:09
Spec for handling processings whose plugin is deleted from the registry
or for which the current owner has lost access. Switches the UI from an
opaque global 404 notification to an explicit read-only + delete-only
state on both the list and the edit page, with a friendly worker log.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Breaks the broken-plugin design into 8 bite-sized tasks: silence the
global notification, soften the list copy, add a test-env helper,
add the worker log line, render the edit-page banner + read-only state,
gate the action buttons, then pin both contracts with API and e2e tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Callers (processing-card, processing edit page) render their own inline
error state; the global notification was duplicate noise.
Covers both the 404 (plugin deleted) and 403 (no access) cases. Tooltip
echoes the edit-page banner so users get the full explanation on hover.
Lets tests put processings into broken states the normal API guards
prevent — e.g. a pluginId that doesn't resolve in the registry.
Wrap ensureArtefact in try/catch; on 404 (deleted) or 403 (no access)
add a clear French log.error line before re-throwing. The run still
fails with status 'error' exactly as before.
Catch 404/403 from the registry artefact fetch, set pluginBroken, show
a v-alert explaining the state. The config-schema fetch's own 404 is
unchanged (separate, narrower state that does not trigger the banner).
Plumbs pluginBroken to processing-actions so the trigger/duplicate/
change-owner actions can be hidden — see next task.
If the page component is reused on intra-app navigation, the prior
broken-state would persist into a healthy processing. Reset at the
top of the function.
Delete remains so the user can clean up. Triggered by the new
plugin-broken prop wired from the edit page in the previous commit.
GET still works, PATCH surfaces the registry's 404/403, DELETE works.
Uses the new test-env raw-processing PATCH to set up the broken state.

Note: in the current implementation PATCH returns 500 (the registry 404
is not forwarded); the expectation accepts [403, 404, 500] so the test
still passes if forwarding is improved later.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Closes the spec-mandated test that triggers a run on a broken processing
and verifies the run-log contains the French explanation from the
worker's try/catch around ensureArtefact.

Also fix the catch condition in worker/src/task/task.ts: the
AxiosRequestError produced by lib-node-registry carries the HTTP status
on the `.status` property (not `.statusCode`), so the 404/403 guard
was never matching and the friendly French log line was never written.
Changed to `err?.status ?? err?.statusCode` to cover both conventions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
albanm added 5 commits May 19, 2026 12:09
Plugins published as branch (rolling, version-less) artefacts in the
registry can now be selected from the processing picker and resolved at
run time. The pluginId for such processings is just the artefact id (no
@major suffix) — parsePluginId now returns major-optional and the api +
worker paths route to ensureBranchArtefact when major is absent.

Picker, processing card and detail page render a 'dev: <branch>' chip
when the underlying artefact has format=branch, signalling to users
that the tarball can change between runs.

Bumps @data-fair/lib-node-registry to ^0.3.0 (api + worker) for the new
ensureBranchArtefact export.

Tests: parsePluginId unit cases for both shapes; api spec creating and
running a processing against a branch artefact (skipped until the
registry container image carries the /artefacts/branch/:name endpoint).
@albanm albanm merged commit a061246 into master May 20, 2026
1 of 2 checks passed
@albanm albanm deleted the feat-registry branch May 20, 2026 14:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant